package cn.example.base.service.impl;

import cn.example.base.Base;
import cn.example.base.bean.BaseBean;
import cn.example.base.dao.BaseDAO;
import cn.example.base.service.BaseService;
import cn.example.util.ToolFactory;
import cn.example.util.annotation.*;
import cn.example.util.enumerate.GenerationType;
import cn.example.util.enumerate.ResultCode;
import cn.example.util.toolkit.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;

/**
 * Created by WuYB on 2017/11/21.
 */
public class BaseServiceImpl<T> extends Base implements BaseService<T> {

    /**
     * 泛型的数据库类型
     */
    private Class<T> clazz;
    @Resource
    private BaseDAO baseDAO;

    @SuppressWarnings("unchecked")
    public BaseServiceImpl() {
        clazz = (Class<T>) beanUtil.getGenericClass(getClass());
    }

    @Override
    public int insert(T t) {
        String tableName = getTableName();
        List<Map<String, Object>> keyValues = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        Field autoID = null;
        try {
            for (Field field : fields) {
                if (beanUtil.isStaticOrFinal(field)) {
                    continue;
                }
                field.setAccessible(true);
                Object value = field.get(t);
                GeneratedValue generated = beanUtil.getFieldAnnotation(field, GeneratedValue.class);
                if (generated != null) {
                    if (generated.type() == (GenerationType.ID)) {//跳过自增ID
                        autoID = field;
                        continue;
                    }
                    if (generated.type() == (GenerationType.UUID)) {//UUID赋值
                        value = UUID.randomUUID().toString();
                        field.set(t, value);
                    }
                    if (generated.type() == (GenerationType.DATE)) {//Date赋值
                        value = new Date();
                        field.set(t, value);
                    }
                }
                Map<String, Object> keyValue = new HashMap<>();
                keyValue.put("key", field.getName());
                keyValue.put("value", value);
                keyValues.add(keyValue);
            }
        } catch (ReflectiveOperationException e) {
            log.error("解析数据库映射对象异常！", e);
            return ResultCode.ERROR.value();
        }
        BaseBean base = new BaseBean();
        base.setTable(tableName);
        base.setKeyValues(keyValues);
        if (baseDAO.insert(base) > 0) {
            if (autoID != null) {//自增ID赋值
                try {
                    autoID.setAccessible(true);
                    autoID.set(t, base.getId());
                } catch (ReflectiveOperationException e) {
                    log.error("保存成功，自增ID赋值异常！", e);
                }
            }
            return ResultCode.SUCCESS.value();
        }
        return ResultCode.ERROR.value();
    }

    @Override
    public int update(T t) {
        try {
            String tableName = getTableName();
            List<Map<String, Object>> keyValues = new ArrayList<>();
            Field[] fields = clazz.getDeclaredFields();
            String primaryKey = null;
            String primaryValue = null;
            for (Field field : fields) {
                if (beanUtil.isStaticOrFinal(field)) {
                    continue;
                }
                field.setAccessible(true);
                Object value = field.get(t);
                if (beanUtil.isAnnotationField(field, PrimaryKey.class)) {//主键
                    primaryKey = field.getName();
                    primaryValue = String.valueOf(field.get(t));
                    continue;
                }
                GeneratedValue generated = beanUtil.getFieldAnnotation(field, GeneratedValue.class);
                if (generated != null) {
                    if (generated.type() == (GenerationType.ID)) {//跳过自增ID
                        continue;
                    }
                    if (generated.update() && generated.type() == (GenerationType.UUID)) {//UUID赋值
                        value = UUID.randomUUID().toString();
                        field.set(t, value);
                    }
                    if (generated.update() && generated.type() == (GenerationType.DATE)) {//Date赋值
                        value = new Date();
                        field.set(t, value);
                    }
                }
                if (nullUtil.isNullObj(value)) {//空字段过滤
                    continue;
                }
                Map<String, Object> keyValue = new HashMap<>();
                keyValue.put("key", field.getName());
                keyValue.put("value", value);
                keyValues.add(keyValue);
            }
            if (keyValues.size() > 0) {
                BaseBean base = new BaseBean();
                base.setTable(tableName);
                base.setPrimaryKey(primaryKey);
                base.setPrimaryValue(primaryValue);
                base.setKeyValues(keyValues);
                return baseDAO.update(base);
            } else {
                return ResultCode.ERROR.value();
            }
        } catch (ReflectiveOperationException e) {
            log.error("解析数据库映射对象异常！", e);
            return ResultCode.ERROR.value();
        }
    }

    @Override
    public int delete(String pk) {
        String tableName = getTableName();
        List<Field> fields = beanUtil.getAnnotationFields(clazz, PrimaryKey.class);
        if (fields.size() == 1) {
            Field field = fields.get(0);
            field.setAccessible(true);
            return baseDAO.delete(tableName, field.getName(), pk);
        } else {
            throw new RuntimeException("无主键或有多个主键！");
        }
    }

    @Override
    public T get(String pk) {
        String tableName = getTableName();
        List<Field> fields = beanUtil.getAnnotationFields(clazz, PrimaryKey.class);
        if (fields.size() == 1) {
            Field field = fields.get(0);
            field.setAccessible(true);
            Map<String, Object> map = baseDAO.get(tableName, field.getName(), pk);
            return beanUtil.map2Obj(map, clazz);
        } else {
            throw new RuntimeException("无主键或有多个主键！");
        }
    }

    private String getTableName() {
        Table table = beanUtil.getTypeAnnotation(Table.class, clazz);
        return nullUtil.isNull(table.name()) ? clazz.getSimpleName() : table.name();
    }

    /**
     * 事务手动回滚
     */
    protected void rollBack() {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }

}
